package com.conversationboard.model;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.conversationboard.model.propertybag.Property;
import com.conversationboard.model.propertybag.PropertyBag;
import com.conversationboard.serialisation.XmlSerialiser;

public class Substitutions extends HashMap<String, Substitution> {

    private static final long serialVersionUID = 1333110665734750790L;
    private transient ReadWriteLock lockManager = new ReentrantReadWriteLock();


    /** Load the substitutions in from the Database's property bag */

    public Substitutions() {

        try {
            Property property = PropertyBag.get("substitutions");

            if (property == null) {
                return;
            }

            String xml = property.getValue();

            XmlSerialiser<Substitutions> serialiser = new XmlSerialiser<Substitutions>();
            serialiser.setAlias("Substitution", Substitution.class);
            serialiser.setAlias("Substitutions", Substitutions.class);

            Substitutions substitutions = serialiser.deSerialise(xml);
            for (Substitution substitution : substitutions.values()) {
                this.put(substitution.getId(), substitution);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public void addSubstitution(String loginId, String ipAddress, String regularExpression, String substitutionTerm) throws SQLException {

        Lock lock = lockManager.writeLock();

        Substitution substitution = new Substitution();
        substitution.setLoginId(loginId);
        substitution.setIpAddress(ipAddress);
        substitution.setRegularExpression(regularExpression);
        substitution.setSubstitution(substitutionTerm);

        try {
            lock.lock();

            this.put(substitution.getId(), substitution);
            this.store();

        } finally {
            lock.unlock();
        }

    }


    /**
     * Remove a substitution. Note: doesn't store it; relies on the caller to store it.
     * 
     * @param id
     * @throws SQLException
     */
    
    public void removeSubstitution(String id) throws SQLException {

        Lock lock = lockManager.writeLock();

        try {
            lock.lock();
            this.remove(id);

        } finally {
            lock.unlock();
        }

    }


    private String makeSubstitution(Substitution substitution, String message) {
        
        Pattern pattern = substitution.getPattern();
        Matcher matcher = pattern.matcher(message);
        
        return matcher.replaceAll(substitution.getSubstitution());
    }


    public String substitute(User user, String message) {

        Lock lock = lockManager.readLock();

        String ipAddress = user.getIpAddress();

        if (ipAddress == null) {
        	ipAddress = "";
        }
        
        try {

            lock.lock();

            for (Substitution substitution : this.values()) {

                if (substitution.getIpAddress().equals(ipAddress) || substitution.getLoginId().equals(user.getLoginId()) || (substitution.getLoginId().equals("*"))) {
                    message = this.makeSubstitution(substitution, message);
                }
            }

            return message;

        } finally {
            lock.unlock();
        }

    }


    public void store() throws SQLException {

        XmlSerialiser<Substitutions> serialiser = new XmlSerialiser<Substitutions>();
        serialiser.setAlias("Substitution", Substitution.class);
        serialiser.setAlias("Substitutions", Substitutions.class);

        String xml = serialiser.serialise(this);

        PropertyBag.put("substitutions", xml);

    }

}
